package server

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

// HTTP 服务端
func Start() {
	fmt.Println("Http 服务端启动...")

	// 登录
	http.HandleFunc("/login", handleLogin)
	// 根据手机号查找信息
	http.HandleFunc("/findUserByPhone", handleFindUserByPhone)
	// 查询列表
	http.HandleFunc("/findList", handleFindList)
	// 文件上传
	http.HandleFunc("/uploadFile", handleUploadFile)
	// 查询所有上传文件
	http.HandleFunc("/listFile", handleListFile)
	// 下载文件
	http.HandleFunc("/downloadFile", handleDownloadFile)

	// 启动服务器
	//http.ListenAndServe("127.0.0.1:60000", nil)
	if err := http.ListenAndServe(":60000", nil); err != nil {
		fmt.Printf("服务器启动错误: %v\n", err)
	}

}

// 用户 - 结构体
type user struct {
	Id    int    `json:"id"`
	Name  string `json:"name"`
	Sex   bool   `json:"sex"`
	Phone string `json:"phone"`
	Pwd   string `json:"pwd"`
	Email string `json:"email"`
}

// 模拟用户数据
var userList = []user{
	{Id: 1, Name: "丽丽", Sex: false, Phone: "13502310214", Pwd: "123456"},
	{Id: 2, Name: "小红", Sex: false, Phone: "13502310215", Pwd: "123456", Email: "234@163.com"},
	{Id: 3, Name: "张三", Sex: true, Phone: "13602310214", Pwd: "123456", Email: "343@163.com"},
}

/*
 * 登录处理
 */
func handleLogin(w http.ResponseWriter, r *http.Request) {
	fmt.Println("登录连接成功...", r.RemoteAddr, r.RequestURI)
	fmt.Println("\t获取请求方式：", r.Method)
	fmt.Println("\t获取请求路径：", r.URL.Path)
	fmt.Println("\t获取请求头：", r.Header)
	fmt.Println("\t获取请求体：", r.Body)

	if r.Method == http.MethodPost {
		// 读取请求体
		body, err := io.ReadAll(r.Body)
		if err != nil {
			http.Error(w, "\t请求体失败", http.StatusBadRequest)
			return
		}
		defer r.Body.Close() //关闭

		// 获取请求内容
		strBody := string(body)
		fmt.Println("\t接收请求体：", strBody)

		// 将读取内容转map
		var bodyMap map[string]interface{}
		err = json.Unmarshal([]byte(strBody), &bodyMap)
		if err != nil {
			panic(err)
		}

		// 定义校验账号结果
		checkPhoneFlag := false
		checkPhoneRes := map[bool]string{
			true:  "账号正确",
			false: "账号有误",
		}

		for _, v := range userList {
			if v.Phone == bodyMap["Phone"] {
				fmt.Println("账号有效..")
				checkPhoneFlag = true
				break
			}
		}
		// 使用map结构方式，来实现三元判断
		fmt.Println("\t处理登录结果：", checkPhoneRes[checkPhoneFlag])

		// 返回JSON登录结果信息，给客户端
		resMap := map[string]interface{}{
			"code":    200,
			"message": checkPhoneRes[checkPhoneFlag],
			"data":    "",
		}
		fmt.Println("\t返回JSON登录结果信息：", resMap)
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(200)
		json.NewEncoder(w).Encode(resMap)
		fmt.Println("登录响应处理完成...", r.RemoteAddr, r.RequestURI)

	}

}

/*
 * 根据手机号查找信息处理
 */
func handleFindUserByPhone(w http.ResponseWriter, r *http.Request) {
	fmt.Println("根据手机号查找信息连接成功...", r.RemoteAddr, r.RequestURI)
	fmt.Println("\t获取请求方式：", r.Method)
	fmt.Println("\t获取请求路径：", r.URL.Path)
	fmt.Println("\t获取请求头：", r.Header)

	// 读取请求来的字符串
	if _, err := io.ReadAll(r.Body); err != nil {
		fmt.Println("\t解析响应失败:", err)
		return
	}
	defer r.Body.Close()

	// 获取请求路径中携带参数
	pathParam := r.URL.Query()
	fmt.Printf("\t获取请求路径参数：%v  类型string \n", pathParam.Get("phone"))

	// 校验请求参数
	if pathParam.Get("phone") == "" {
		fmt.Println("参数不能为空！")
		w.Write([]byte("参数不能为空！"))
		return
	}

	checkPhoneFlag := false
	for _, v := range userList {
		if v.Phone == pathParam.Get("phone") {
			checkPhoneFlag = true
			break
		}
	}

	// 使用匿名函数返回结果信息
	resMsg := func() string {
		if checkPhoneFlag {
			return "查询成功"
		}
		return "未查询到该用户信息"
	}()
	fmt.Println(resMsg)
	w.Write([]byte(resMsg))
	fmt.Println("根据手机号查找信息响应处理完成...", r.RemoteAddr, r.RequestURI)
}

// ----------------------------------------------------------------------
// API-响应结构体
type Result struct {
	Code    int         `json:"code"`
	Success bool        `json:"success"`
	Message string      `json:"message"`
	Data    interface{} `json:"data,omitempty"`
}

// 发送JSON响应 支持任意数据
func sendJSONResponse(w http.ResponseWriter, data interface{}, statusCode int) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(statusCode)
	json.NewEncoder(w).Encode(data)
}

/*
 * 查询列表 处理
 */
func handleFindList(w http.ResponseWriter, r *http.Request) {
	fmt.Println("查询列表连接成功...", r.RemoteAddr, r.RequestURI)
	fmt.Println("\t获取请求方式：", r.Method)
	fmt.Println("\t获取请求路径：", r.URL.Path)
	fmt.Println("\t获取请求头：", r.Header)

	res := Result{
		Code:    200,
		Success: true,
		Message: "操作成功",
		Data:    userList,
	}
	fmt.Println("\t返回响应体：", res)
	sendJSONResponse(w, res, res.Code)
	fmt.Println("查询列表响应处理完成...", r.RemoteAddr, r.RequestURI)
}

/*
 * 文件上传 处理
 */
func handleUploadFile(w http.ResponseWriter, r *http.Request) {
	// 解析 multipart 表单，最大内存32MB
	r.ParseMultipartForm(32 << 20)

	// 获取上传的文件
	file, header, err := r.FormFile("file")
	if err != nil {
		log.Println("上传文件失败，", err)
		return
	}
	defer file.Close()

	// 创建保存文件目录
	uploadDir := "./uploads"
	if err := os.MkdirAll(uploadDir, 0777); err != nil {
		log.Println("创建保存文件目录错误，", err)
		return
	}

	// 创建目标文件
	filename := filepath.Join(uploadDir, header.Filename)
	dst, err := os.Create(filename)
	if err != nil {
		log.Println("创建目标文件错误，", err)
		return
	}
	defer dst.Close()

	// 复制文件内容
	if _, err := io.Copy(dst, file); err != nil {
		log.Println("保存文件错误，", err)
		return
	}
	fmt.Printf("文件上传成功: %s (大小: %d bytes)", header.Filename, header.Size)
}

/*
 * 查询所有上传文件 处理
 */
func handleListFile(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		log.Println("支持支GET请求")
		return
	}

	uploadDir := "./uploads"
	files, err := os.ReadDir(uploadDir)
	if err != nil {
		log.Println("读取目录错误， ", err)
		return
	}

	var fileArr []string //定义存放查询到的文件容器
	for _, file := range files {
		if !file.IsDir() { //判断当前file 不是目录
			fileArr = append(fileArr, file.Name())
		}
	}

	// 数组转字符串，用逗号分割
	fileStr := strings.Join(fileArr, ", ")
	fmt.Println(fileStr)
	w.Write([]byte(fileStr)) //将存在的文件发送给客户端
}

/*
 * 下载文件 处理
 */
func handleDownloadFile(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		log.Println("支持支GET请求")
		return
	}

	// 获取GET 请求参数
	fileName := r.URL.Query().Get("fileName")
	if fileName == "" {
		log.Println("下载文件参数不能为空！")
		return
	}

	// 拼接完整路径
	filePath := filepath.Join("./uploads", fileName)

	// 检查文件是否存在
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		log.Println("文件不存在")
		return
	}

	// 设置响应头
	w.Header().Set("Content-Disposition", "attachment; filename="+fileName)
	w.Header().Set("Content-Type", "application/octet-stream")

	// 发送文件
	http.ServeFile(w, r, filePath)

}
